use chrono::{DateTime, Local};
use crate::db::dao::im_session_dao::{session_all, session_by_user_id_and_time_and_size, session_get_by_group_code_and_user_id, session_get_by_user_id, session_inserts, session_total, session_update, session_updates};
use crate::db::db::Db;
use crate::db::db_transaction::transaction;
use crate::db::pojo::pojo::{ImSession};

pub struct ImSessionService;

impl ImSessionService {

    pub(crate) fn save_sessions(&self, mut sessions: &mut Vec<ImSession>) {
        let db = Db::open();
        self.save_sessions_business(db.clone(), &mut sessions);
    }

    pub(crate) fn update(&self, session: &mut ImSession) {
        let db = Db::open();
        session_update(db.clone(), session);
    }

    pub(crate) fn updates(&self, mut sessions: &mut Vec<&mut ImSession>) {
        let db = Db::open();
        session_updates(db.clone(), &mut sessions);
    }

    pub fn updates2(&self, db: Db, sessions: &mut Vec<ImSession>) {
        let mut s = sessions.iter_mut().collect::<Vec<&mut ImSession>>();
        session_updates(db.clone(), &mut s);
    }
    
    pub fn hot_message_total(user_id: String, size: usize)-> Vec<ImSession> {
        let db = Db::open();
        session_all(db.clone(), &user_id, 0,size)
    }

    pub(crate) fn get_by_group_code_and_user_id(&self, group_code: &str, user_id: &str) -> Option<ImSession> {
        let db = Db::open();
        session_get_by_group_code_and_user_id(db.clone(), group_code, user_id)
    }

    pub(crate) fn get_by_user_id(&self, user_id: &str, from_user_id: &str, to_user_id: &str) -> Option<ImSession> {
        let db = Db::open();
        session_get_by_user_id(db.clone(), user_id, from_user_id, to_user_id)
    }

    pub(crate) fn get_by_user_id_and_time_and_size(&self, user_id: String, start_time: DateTime<Local>, start: usize, size: usize) -> Vec<ImSession> {
        let db = Db::open();
        session_by_user_id_and_time_and_size(db.clone(), user_id, start_time, start, size)
    }

    pub(crate) fn query(&self, user_id: &str, start: usize, size: usize) -> Vec<ImSession> {
        let db = Db::open();
        session_all(db.clone(), user_id, start, size)
    }

    pub fn total(&self)->usize {
        let db = Db::open();
        let total = transaction(db.clone(), move |db: Db| {
            session_total(db)
        });
        total
    }

    fn save_sessions_business(&self, db: Db, sessions: &mut Vec<ImSession>) {
        log::info!("save sessions, data: {:?}", sessions);

        let mut insert_sessions= Vec::new();
        let mut update_sessions = Vec::new();

        for session in sessions.iter_mut() {
            let group_code = session.group_code.clone();
            let from_user_id = &session.from_user_id;
            match group_code {
                None => {
                    let current_user_id = &session.current_user_id;
                    let to_user_id = &session.to_user_id.clone().unwrap();
                    let db_session = session_get_by_user_id(db.clone(), current_user_id, from_user_id, to_user_id);
                    self.merge_db_session(&mut *session, db_session, &mut insert_sessions, &mut update_sessions);
                }
                Some(group_code) => {
                    let db_session = session_get_by_group_code_and_user_id(db.clone(), &group_code, from_user_id);
                    self.merge_db_session(&mut *session, db_session, &mut insert_sessions, &mut update_sessions);
                }
            }
        }

        session_inserts(db.clone(), &mut insert_sessions);
        session_updates(db.clone(), &mut update_sessions);
    }

    fn merge_db_session<'a>(&self, session: &'a mut ImSession, db_session: Option<ImSession>, insert_sessions: &mut Vec<&'a mut  ImSession>, update_sessions: &mut Vec<&'a mut ImSession>) {
        if db_session.is_none() {
            insert_sessions.push(&mut *session);
        } else {
            let db_session = db_session.unwrap();
            session.id = db_session.id.clone();
            session.lately_message = db_session.lately_message.clone();
            session.hot_message_total = db_session.hot_message_total.clone();
            session.update_time = Local::now();
            update_sessions.push(&mut *session);
        }
    }
}
